import applyMixin from "./mixin";
import ModuleCollection from "./module/module-collection";

import { forEach } from "./util";
let Vue;

function getState(store,path){
   return path.reduce((newState,current)=>{
        return newState[current];
    },store.state);
}

function installModule(store, rootState, path, module) {
    //注册事件时，需要注册到对应的命名空间中 path是所有路径，根据path算出一个空间
    let namespace = store._modules.getNamespace(path);
    console.log(namespace, "namespace");
    //[b,c]
    if (path.length > 0) {
        //子模块需要将子模块状态定义到根模块
        let parent = path.slice(0, -1).reduce((memo, current) => {
            return memo[current];
        }, rootState);
        //vue set会区分是否响应式数据
        store._withCommitting(()=>{
            Vue.set(parent, path[path.length - 1], module.state);
        })
    }
    module.forEachMutation((mutation, type) => {
        console.log(mutation, type, "allmuuuu");
        store._mutations[namespace + type] = store._mutations[namespace + type] || [];
        store._mutations[namespace + type].push(payload => {
            //内部可能会替换状态,这里如果一直用module.state 可能就是老的状态
            // mutation.call(store, module.state, payload); //更改状态
            store._withCommitting(()=>{
                mutation.call(store, getState(store,path), payload); //更改状态
            })
            //调用订阅的事件 重新执行
            store._subscribers.forEach(sub =>
                sub({ mutation, type }, store.state)
            );
        });
    });
    module.forEachAction((action, type) => {
        store._actions[namespace + type] = store._actions[namespace + type] || [];
        store._actions[namespace + type].push(payload => {
            action.call(store, store, payload);
        });
    });
    //getters重名会覆盖 所有模块的getters都会定义到根模块
    module.forEachGetters((getter, key) => {
        store._wrappedGetters[namespace + key] = function(params) {
            return getter(getState(store,path));
        };
    });

    module.forEachChild((child, key) => {
        installModule(store, rootState, path.concat(key), child);
    });
}
function resetStoreVm(store, state) {
    const wrappedGetters = store._wrappedGetters;
    let oldVm = store._vm;
    let computed = {};
    store.getters = {};
    forEach(wrappedGetters, (fn, key) => {
        computed[key] = function() {
            return fn();
        };
        Object.defineProperty(store.getters, key, {
            get: () => store._vm[key]
        });
    });
    store._vm = new Vue({
        data: {
            $$state: state
        },
        computed
    });

    if(store.strict) {
        store._vm.$watch(()=>store._vm._data.$$state,()=>{
              console.assert(store._committing,'在mutation之外更改了状态')
        },{deep:true,sync:true});
    }

    if (oldVm) {
        Vue.nextTick(() => oldVm.$destroyed());
    }
}
//最终用户拿到的是这个类的实例
class Store {
    constructor(options) {
        //格式化用户传入的参数 收集模块转换为树结构
        this._modules = new ModuleCollection(options);
        let state = this._modules.root.state;
        this._mutations = {}; //存放所有模块中的mutations
        this._actions = {}; //存放所有模块中的actions
        this._wrappedGetters = {}; // 存放所有模块中的getters
        this._subscribers = [];
        this.strict= options.strict; //严格模式

        //同步的watcher
        this._committing = false;

        installModule(this, state, [], this._modules.root);
        //将状态放到vue的实例中
        resetStoreVm(this, state);

        //插件的实现
        options.plugins.forEach(plugin => plugin(this));

        console.log(this._mutations, "mmmm");
        //    let state = options.state;

        //    this.getters = {}; //写的是方法 取的是属性
        //    const computed = {};
        //    forEach(options.getters,(fn,key)=>{
        //        computed[key] = ()=>{ //通过计算属性实现懒加载
        //            return fn(this.state);
        //        }
        //        Object.defineProperty(this.getters,key,{
        //            get: ()=> this._vm[key]
        //        })
        //    })

        //vue中定义数据，属性名是有特点的，如果属性名是通过$xxx命名的，他不会被代理到vue的实例上
        // this._vm = new Vue({
        //     data:{
        //        $$state: state //内部的状态
        //     },
        //     computed // 计算属性会将自己的属性放到实例上
        // })

        //发布订阅模式 将用户定义的mutation和dispatch先保存起来，稍后当调用commit时，就找订阅的mutation方法，调用dispatch找对应的action
        // this._mutations = {};
        // forEach(options.mutations,(fn,type)=>{
        //     this._mutations[type] = (payload)=> fn.call(this,this.state,payload)
        // })

        // this._actions = {};
        // forEach(options.actions,(fn,type)=>{
        //     this._actions[type] = (payload)=> fn.call(this,this,payload)
        // })
    }
    _withCommitting(fn){
        let committing = this._committing;
        this._committing = true;
        fn();
        this._committing = committing;
    }
    subscribe(fn) {
        this._subscribers.push(fn);
    }
    commit = (type, payload) => {
        this._mutations[type].forEach(fn => fn(payload));
    };
    dispatch = (type, payload) => {
        this._actions[type].forEach(fn => fn(payload));
    };
    replaceState(newState){ //用最新的状态替换掉
        this._withCommitting(()=>{
            this._vm._data.$$state = newState;
        })
    }
    //类的属性访问器
    get state() {
        return this._vm._data.$$state;
    }
    registerModule(path, rawModule) {
        if (typeof path === "string") path = [path];
        //模块注册
        this._modules.register(path, rawModule);
        //安装模块
        installModule(this, this.state, path, rawModule.newModule);
        //重新定义getters
        // resetStoreVm(this,this.state);
    }
}
const install = _Vue => {
    Vue = _Vue;
    applyMixin(Vue);
};
export { Store, install };
